home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir34
/
2m21src.zip
/
2M-ABIOS.ASM
next >
Wrap
Assembly Source File
|
1994-05-31
|
119KB
|
2,884 lines
;*********************************************************************
;* *
;* 2M-ABIOS 1.2 - (C) Mayo 1994 Ciriaco García de Celis. *
;* *
;* Código para emular al 100% la BIOS AMI de 1993. *
;* *
;* Si el ordenador posee disco duro, la INT 40h controla los *
;* accesos a disquete. Desviar esta interrupción en lugar de *
;* la INT 13h permite que este programa tome el control de *
;* las disqueteras antes que cualquier otro (incluso aunque *
;* se instale después) y además permite seguir trabajando al *
;* código del DOS que, desde INT 13h, soluciona el cruce con *
;* las fronteras de DMA antes de invocar a la INT 40h. *
;* *
;* Si el ordenador no utilizase la INT 40h en los accesos a *
;* las disqueteras se desvía INT 13h y se cuelga este código *
;* de la misma, cuidando evitar un cruce con el DMA a través *
;* de un buffer intermedio auxiliar si es preciso. *
;* *
;* Ensamblar con TASM /m5 y linkar con TLINK para obtener un *
;* fichero EXE que se instala con DEVICE desde el CONFIG.SYS *
;* *
;*********************************************************************
.286
; ------------ Macros de propósito general.
XPUSH MACRO regmem ; apilar lista de registros
IRP rm, <regmem>
PUSH rm
ENDM
ENDM
XPOP MACRO regmem ; desapilar lista de registros
IRP rm, <regmem>
POP rm
ENDM
ENDM
; ************ Inicio del área residente.
_PRINCIPAL SEGMENT
ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
ORG 0
ini_residente EQU $
DD -1 ; encadenamiento con otros drivers
tipo_drive DW 8000h ; palabra de atributo:
; bit 15 a 1: dispositivo caracteres
; bit 14 a 0: sin control IOCTL
DW estrategia ; rutina de estrategia
DW interrupcion ; rutina de interrupción
DB "2M-BIOS$" ; nombre del dispositivo
estrategia PROC FAR
MOV CS:pcab_pet_segm,ES
MOV CS:pcab_pet_desp,BX
RET
estrategia ENDP
interrupcion PROC FAR
CALL main ; tras instalar: XPUSH <DS, BX> y MOV BX,??
pcab_pet_segm DW ?
MOV DS,BX
DB 0BBh ; opcode de MOV BX,??
pcab_pet_desp DW ?
MOV WORD PTR [BX+3],8103h ; código de error
XPOP <BX, DS>
RET
interrupcion ENDP
; ****************************************
; * *
; * D A T O S R E S I D E N T E S *
; * *
; ****************************************
; ------------ Identificación estandarizada del programa.
program_id LABEL BYTE
segmento_real DW 0 ; segmento real donde será cargado
offset_real DW 0 ; offset real " " "
longitud_total DW 0 ; zona de memoria ocupada (párrafos)
info_extra DB 03h ; bits 0, 1 y 2-> 000: normal, con PSP
; 001: bloque UMB XMS
; 010: *.SYS
; 011: *.SYS formato EXE
; bit 7 a 1: «extension_id» definida
multiplex_id DB 0 ; número Multiplex de este TSR
vectores_id DW tabla_vectores
extension_id DW 0
DB "*##*"
autor_nom_ver DB "CiriSOFT:2M-ABIOS:1.2",0
DB 2 ; número de vectores de interrupción usados
tabla_vectores EQU $
DB 2Fh ; INT 2Fh
ant_int2F LABEL DWORD ; dirección original
ant_int2F_off DW 0
ant_int2F_seg DW 0
DB 40h ; INT 40h
ant_int40 LABEL DWORD ; dirección original
ant_int40_off DW 0
ant_int40_seg DW 0
DB 13h ; INT 13h podría llegar a usarse
ant_int13 LABEL DWORD
ant_int13_off DW 0
ant_int13_seg DW 0
; ***************************************
; * *
; * C O D I G O R E S I D E N T E *
; * *
; ***************************************
; ------------ Rutina de gestión de INT 2Fh.
ges_int2F PROC FAR
STI
CMP AH,CS:multiplex_id
JE preguntan
JMP CS:ant_int2F ; saltar al gestor de INT 2Fh
preguntan: CMP DI,1992h
JNE ret_no_info ; no llama alguien del convenio
MOV AX,ES
CMP AX,1492h
JNE ret_no_info ; no llama alguien del convenio
PUSH CS
POP ES ; sí llama: darle información
LEA DI,autor_nom_ver
ret_no_info: MOV AX,0FFFFh ; "entrada multiplex en uso"
IRET
ges_int2F ENDP
; ------------ Rutina de control de INT 40h.
r_flags EQU WORD PTR [BP+18h] ; constantes para parámetros
r_flags_l EQU BYTE PTR [BP+18h]
r_flags_h EQU BYTE PTR [BP+19h]
r_ax EQU WORD PTR [BP+12h]
r_al EQU BYTE PTR [BP+12h]
r_ah EQU BYTE PTR [BP+13h]
r_cx EQU WORD PTR [BP+10h]
r_cl EQU BYTE PTR [BP+10h]
r_ch EQU BYTE PTR [BP+11h]
r_dx EQU WORD PTR [BP+0Eh]
r_dl EQU BYTE PTR [BP+0Eh]
r_dh EQU BYTE PTR [BP+0Fh]
r_bx EQU WORD PTR [BP+0Ch]
r_bl EQU BYTE PTR [BP+0Ch]
r_bh EQU BYTE PTR [BP+0Dh]
r_bp EQU WORD PTR [BP+0Ah]
r_si EQU WORD PTR [BP+08h]
r_di EQU WORD PTR [BP+06h]
r_ds EQU WORD PTR [BP+04h]
r_es EQU WORD PTR [BP+02h]
ges_int40 PROC
STI
CLD
PUSH AX
PUSH CX
PUSH DX
PUSH BX
PUSH BP
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH BP
MOV BP,SP
PUSH 40h
POP DS
PUSH AX
MOV AL,AH
CMP AL,18h
JA mal_funcion
CMP AL,5
JBE func_oper
CMP AL,8
JNE func_aux?
MOV AL,6
JMP func_oper
func_aux?: CMP AL,15h
JB mal_funcion
SUB AL,0Eh
func_oper: CBW
MOV DI,AX
POP AX
SHL DI,1
JMP CS:tab_jmp[DI] ; ejecutar función
main_exit: MOV AL,AH ; preservar resultado
LAHF ; preservar flags
PUSH AX
PUSH 40h
POP DS
MOV AL,r_dl ; DL a la llamada (unidad)
CMP AL,1
JA u_det ; unidad incorrecta
XOR AH,AH
MOV BX,90h
ADD BX,AX ; [BX] -> estado físico unidad
TEST BYTE PTR DS:[BX],10h ; ¿densidad determinada?
JZ u_det ; no
MOV DL,4 ; sí
MUL DL
MOV CL,AL
SHL DL,CL
OR DS:[8Fh],DL ; unidad determinada
u_det: POP AX
SAHF ; recuperar flags
MOV AH,AL ; recuperar resultado
exit_i40: MOV r_ah,AH ; AH para la salida del IRET
MOV AX,201H ; STI + STC en flags
JC set_err ; hay error
AND r_flags_l,0FEH ; CLC (si no hay error)
DEC AX ; dejar sólo STI
set_err: OR r_flags,AX ; flags a la salida del IRET
POP BP
POP ES
POP DS
POP DI
POP SI
POP BP
POP BX
POP DX
POP CX
POP AX ; registros con resultado
IRET
ges_int40 ENDP
mal_funcion: POP AX
MOV AH,1 ; función/parámetro incorrecto
MOV DS:[41h],AH ; código de error
STC ; condición de error
JMP exit_i40
; ------------ Función 0: Resetear el sistema de disco.
reset PROC
CALL full_init ; inicialización plena
MOV DS:[41h],AH ; código de error
MOV AL,AH ; preservar código
LAHF ; preservar flags
PUSH AX
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV CL,[SI+2]
POP DS
MOV DS:[40h],CL ; tics para detención motor
POP AX
SAHF
MOV AH,AL ; restaurado código y flags
JMP exit_i40
reset ENDP
; ------------ Inicialización plena.
full_init PROC
AND BYTE PTR DS:[3Eh],0F0h ; futuro recalibramiento
JMP init_fdc ; inicializar FDC
fdc_init: JC init_end
JMP send_specify ; enviar specify
specify_sent: JC init_end
XOR AH,AH ; no hay error
init_end: RET
full_init ENDP
; ------------ Función 1: Obtener resultado de la última operación.
get_status PROC
MOV AH,DS:[41h]
OR AH,AH
JZ no_err
STC
no_err: JMP exit_i40
get_status ENDP
; ------------ Función 15h: Obtener el tipo de disco.
get_disk_type PROC
CMP DL,1
JBE gdt_ok
MOV AH,1 ; función/parámetro incorrecto
STC
MOV DS:[41h],AH ; código de error
JMP gdt_exit
gdt_ok: MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico unidad
MOV BL,[BX] ; estado físico de la unidad
OR BL,BL
JNZ gdt_posible
XOR AH,AH ; no existe tal unidad
JMP gdt_bye
gdt_posible: AND BL,7
JZ gdt_without ; 360K
CMP BL,3
JE gdt_without ; 360K
MOV AH,2
JMP gdt_bye ; con soporte cambio de línea
gdt_without: MOV AH,1 ; sin soporte cambio de línea
gdt_bye: CLC
MOV BYTE PTR DS:[41h],0 ; siempre sin error
gdt_exit: JMP main_exit
get_disk_type ENDP
; ------------ Función 17h: Establecer tipo de soporte para formateo.
set_type_fmt PROC
XOR AH,AH
CMP DL,1
JBE set_tp
set_tp_bad_p: MOV AH,1 ; función/parámetro incorrecto
set_tp_err: MOV DS:[41h],AH ; código de error
STC
JMP set_tp_exit
set_tp: CMP AL,0 ; validar parámetro
JE set_tp_bad_p
CMP AL,4
JA set_tp_bad_p
MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico unidad
CMP AL,1 ; ¿360K en 360K?
JNE set_tp_n360
MOV BYTE PTR DS:[BX],93h ; actualizar variable tipo
MOV BYTE PTR DS:[41h],0 ; anular errores previos
JMP set_tp_t_exit
set_tp_n360: MOV CX,AX
PUSH BX
CALL motor_on ; arrancar motor
POP SI
PUSH SI
CALL read_disk_chg ; ¿cambio de disco?
POP BX
CMP AH,6 ; (0: no, 6: sí)
JBE set_tp_cd ; haya cambio o no
CMP AH,80h
JNE set_tp_cd ; sí existe disco
CMP BYTE PTR DS:[BX],97h ; ¿250 Kbps y no es 5.25?
JE set_tp_err ; error
MOV BYTE PTR DS:[BX],61h ; 300 Kbps, try 360 en 1.2
JMP set_tp_err ; error
set_tp_cd: CMP CL,4 ; ¿720K en 720K?
JNE set_tp_n720 ; no
MOV BYTE PTR DS:[BX],97h ; actualizar variable tipo
JMP set_tp_t_exit
set_tp_n720: CMP CL,2 ; ¿360K en 1.2M?
JNE set_tp_ndd ; no
MOV BYTE PTR DS:[BX],74h ; actualizar variable tipo
JMP set_tp_t_exit
set_tp_ndd: MOV BYTE PTR DS:[BX],15h ; 1.2M en 1.2M
set_tp_t_exit: OR AH,AH ; comprobar posible error
JNZ set_tp_err
MOV BYTE PTR DS:[41h],0
set_tp_exit: JMP main_exit
set_type_fmt ENDP
; ------------ Función 16h: Detectar cambio de disco.
detect_change PROC
CMP DL,1
JBE det_ch
MOV AH,1 ; función/parámetro incorrecto
det_ch_r_err: STC
JMP det_ch_end
det_ch: XOR DH,DH
MOV BX,90h
ADD BX,DX ; [BX] -> estado físico
CMP BYTE PTR DS:[BX],0 ; ¿estado indeterminado?...
MOV AH,80h ; "unidad no preparada"
JE det_ch_r_err ; ...en efecto
MOV AH,[BX]
AND AH,7
JZ det_ch_yes ; 360K en 360K, no es posible
CMP AH,3
JNE det_ch_calc ; no es 360K en 360K
det_ch_yes: MOV AH,6 ; hay cambio (o desconocido)
STC
JMP det_ch_end
det_ch_calc: CALL motor_on ; arrancar motor
MOV DX,3F7h
IN AL,DX ; leer línea de cambio de disco
SHL AL,1
JC det_ch_yes ; hay cambio de disco
XOR AH,AH ; no lo hay
det_ch_end: MOV DS:[41h],AH ; actualizar código de error
PUSH AX
PUSH SI
PUSH DS
MOV SI,0
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AL,[SI+2]
POP DS
MOV DS:[40h],AL ; tiempo detención motor
POP SI
POP AX
JMP main_exit
detect_change ENDP
; ------------ Funciones 2, 3 y 4: Leer, escribir y verificar.
read_wr_verify PROC
CMP DL,1
JBE rwv_posible
MOV AH,1 ; función/parámetro incorrecto
rwv_err: MOV DS:[41h],AH ; código de error
XOR AL,AL
STC
JMP rwv_exit
rwv_posible: MOV SI,90h
PUSH DX
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico
CMP BYTE PTR DS:[SI],0 ; ¿estado indeterminado?...
POP DX
JNE rwv_state_ok ; no
PUSH AX
CALL get_drive_type ; obtener tipo disquetera en AL
JZ rwv_type_ok ; ha resultado posible
POP AX
rwv_not_ready: MOV AH,80h ; "unidad no preparada"
JMP rwv_err
rwv_type_ok: OR AL,AL ; ¿existe la unidad?
POP AX
JZ rwv_not_ready ; no existe esa unidad
MOV BYTE PTR DS:[SI],2 ; probando 1.2M en 1.2M
rwv_state_ok: MOV DI,3Fh
AND BYTE PTR DS:[DI],7Fh ; operación Read/Verify
CMP AH,3 ; ¿operación de escritura?
JNE rwv_nowr
OR BYTE PTR DS:[DI],80h ; operación Write/Format
rwv_nowr: PUSH SI
CALL get_drive_type ; obtener tipo disquetera en AL
JNZ rwv_media_ok
CMP AL,1
JE rwv_set360 ; es de 360K
CMP AL,3
JNE rwv_media_ok ; no es de 720K
MOV BYTE PTR DS:[SI],97h ; forzar medio de 720K
JMP rwv_media_ok
rwv_set360: MOV BYTE PTR DS:[SI],93h ; forzar medio de 360K
rwv_media_ok: CALL motor_on ; arrancar motores
CALL read_disk_chg ; leer línea de cambio de disco
POP SI
JNC rwv_no_dschg ; no hay cambio de disco
rwv_end_err: CALL end_io_access
JMP rwv_err
rwv_no_dschg: TEST BYTE PTR DS:[SI],10h ; ¿densidad determinada?
JNZ rwv_set_rate ; en efecto
CALL detect_media ; pues determinarla
JC rwv_end_err ; problemas
JMP rwv_dens_ok
rwv_set_rate: CALL select_rate ; seleccionar la velocidad
rwv_dens_ok: MOV SI,90h
PUSH DX
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico unidad
POP DX
MOV AX,0AF03H ; AF byte 0 specify 2.88
CMP BYTE PTR DS:[SI],0D7h ; ¿2.88M?
JE rwv_spec_ok ; así es
MOV AX,0DF03h ; DF para 360/1.2/720
CMP BYTE PTR DS:[SI],17h ; ¿1.44M?
JNE rwv_spec_ok ; no
MOV AH,0BFh ; sí
rwv_spec_ok: MOV SI,AX ; SI 0-7: orden specify
MOV DI,2 ; DI 0-7: byte 1 specify
MOV CH,3 ; comando de 3 bytes
OR BYTE PTR DS:[3Eh],80h ; no esperar INT
CALL exec_cmd
JC rwv_end_err ; fallo
MOV AX,r_ax
XOR AH,AH
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV CL,[SI+3] ; bytes/sector
SHL AL,CL ; multiplicar por nº sectores
MOV CL,80h
MUL CL ; y por 128
POP DS
DEC AX ; un byte menos...
MOV CX,AX ; ...cuenta para el DMA
CALL eval_dir_DMA
JNC rwv_dma_ok ; no hay problemas con el DMA
MOV CX,r_cx ; restaurar CX
JMP rwv_end_err ; problemas con el DMA
rwv_dma_ok: MOV AX,r_ax
CMP AH,2 ; ¿operación de lectura?
JNE rwv_no_read
MOV AH,46h ; byte de modo DMA para lectura
JMP rwv_dma_set
rwv_no_read: CMP AH,3 ; ¿escritura?
MOV AH,4Ah ; modo DMA para escritura
JZ rwv_dma_set
MOV AH,42h ; modo DMA para verificación
rwv_dma_set: CALL set_dma ; preparar DMA
MOV AX,r_ax
MOV CX,r_cx ; restaurar parámetros
JMP perform_io ; efectuar E/S
io_performed: CALL end_io_access
OR AL,AL
JZ rwv_end
SUB BL,CL ; próximo sector-sector inicial
MOV AL,BL ; nº sectores transferidos
rwv_end: MOV AH,DS:[41h]
OR AH,AH ; ¿error?
JZ rwv_exit
STC ; señalizar error
rwv_exit: MOV r_al,AL ; nº sectores transferidos
JMP main_exit
read_wr_verify ENDP
; ------------ Función 5: Formatear pista.
format_track PROC
CMP DL,1
JBE fmt_do
MOV AH,1 ; función/parámetro incorrecto
fmt_exit_err: MOV DS:[41h],AH ; código de error
STC
JMP main_exit
fmt_do: MOV SI,90h
PUSH DX
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico unidad
POP DX
CMP BYTE PTR DS:[SI],0
MOV AH,80h ; "unidad no preparada"
JE fmt_exit_err ; indeterminado
MOV DI,3Fh
OR BYTE PTR DS:[DI],80h ; no esperar INT
CALL motor_on ; arrancar motores
CALL read_disk_chg ; leer línea de cambio de disco
JNC fmt_posible ; no hay cambio de disco
fmt_err: CALL end_io_access
JMP fmt_exit_err ; error
fmt_posible: CALL select_rate ; seleccionar la velocidad
CALL send_specify ; enviar comando specify
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AL,[SI+4] ; sectores por pista
POP DS
XOR AH,AH
MOV CL,4
MUL CL ; 4 bytes para cada uno
MOV CX,AX
DEC CX ; un byte menos...
CALL eval_dir_DMA ; ...cuenta para el DMA
JC fmt_err ; cruza frontera de DMA
MOV AH,4Ah ; modo DMA para escritura
CALL set_dma ; preparar DMA
MOV CX,r_cx ; restaurar CX
CALL seek ; llevar el cabezal a la pista
JNC fmt_continue ; no hay problemas
fmt_err_res: MOV BX,42h
MOV CX,7
PUSH AX
CALL get_results ; leer bytes de resultados
POP AX
JMP fmt_exit ; error
fmt_continue: SHL DH,2
OR DH,DL ; DH = byte 1 del comando
MOV DL,0CDh ; comando de formateo del FDC
PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
PUSH AX
MOV AX,[SI+7] ; GAP formateo/byte de relleno
MOV [BP],AX ; preservarlo
POP AX
MOV DI,[SI+3] ; bytes/sector, sectores/pista
POP DS
MOV SI,DX ; primeros bytes del comando
MOV CH,6 ; comando de 6 bytes
AND BYTE PTR DS:[3Eh],7Fh ; con espera de IRQ
CALL exec_cmd
JC fmt_err_res ; hay error
MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
JC fmt_exit
CALL get_bios_err ; obtener código de error
fmt_exit: MOV DS:[41h],AH ; código de error
CALL end_io_access
MOV AH,DS:[41h]
OR AH,AH
JZ fmt_end ; no hay error
STC
fmt_end: JMP main_exit
format_track ENDP
; ------------ Función 8: Obtener parámetros de disco.
get_drv_param PROC
CMP DL,80h
JB gdrv_do
MOV AH,1 ; función/parámetro incorrecto
MOV DS:[41h],AH ; código de error
STC
JMP main_exit
gdrv_do: XOR DI,DI
XOR SI,SI
XOR DH,DH
MOV AL,DS:[10h] ; hardware instalado
AND AL,0C1h ; nº disqueteras (7-6) y bit
MOV DI,2 ; que indica arrancable (0)
CMP AL,41h ; ¿dos disqueteras? (DI=2)
JE gdrv_ndisk_ok ; en efecto
DEC DI
CMP AL,1 ; ¿una disquetera? (DI=1)
JE gdrv_ndisk_ok ; así es
JMP gdrv_res_null ; no hay disqueteras
gdrv_ndisk_ok: CMP DL,1
JBE gdrv_a_or_b ; la disquetera es A: o B:
JMP gdrv_half_res
gdrv_a_or_b: CALL peek_cmos ; leer tipo de disqueteras
OR DL,DL
JNZ gdrv_sel
MOV CL,4
SHR AL,CL ; dejar disquetera en bits 0-3
gdrv_sel: AND AL,0Fh
JZ gdrv_media? ; no existe esa unidad
CMP AL,5
JA gdrv_media? ; es mayor de 2.88M
XOR AH,AH
MOV SI,AX
MOV DH,AL
MOV BX,90h
ADD BL,DL ; [BX] -> estado físico unidad
MOV AL,[BX]
TEST AL,10h ; ¿densidad determinada?
JNZ gdrv_calc_p ; en efecto
CMP SI,1 ; ¿unidad de 360K?
MOV AL,93h ; 360K en 360K, 250 Kbps
JE gdrv_media_ok
CMP SI,2 ; ¿unidad de 1.2M?
MOV AL,2 ; "intentando 1.2M"
JE gdrv_media_ok
CMP SI,3 ; ¿unidad de 720K?
MOV AL,97h ; 720K en 720K, 250 Kbps
JE gdrv_media_ok
CMP SI,4 ; ¿unidad de 1.44M?
MOV AL,7 ; "intentando 1.44M"
JE gdrv_media_ok
MOV AL,0C7h ; 2.88M en 2.88M
gdrv_media_ok: MOV [BX],AL
JMP gdrv_calc_p ; medio físico asignado
gdrv_media?: MOV BX,90h
ADD BL,DL ; [BX] -> estado físico unidad
MOV AL,[BX]
TEST AL,10h ; ¿densidad determinada?
JZ gdrv_eval ; no
MOV AH,AL
AND AL,0C0h ; aislar bits de velocidad
CMP AL,80h ; ¿250 Kbps?
MOV SI,2 ; 1.2M
JNE gdrv_m144?
TEST AH,4
MOV SI,1 ; 360K
JZ gdrv_calc_p
MOV SI,4 ; 1.44M
gdrv_m144?: TEST AH,7
JZ gdrv_calc_p
MOV SI,4 ; 1.44M
gdrv_calc_p: MOV BX,DI
MOV DI,SI
DEC DI
ADD DI,DI
MOV AX,CS:tab_disksize[DI] ; AL sect/pista, AH pistas
MOV r_dh,1 ; dos cabezales
MOV DI,CS:tab_ptr_1e[DI] ; DI -> tabla parámetros
PUSH CS
POP ES ; ES:DI -> parámetros disco
gdrv_set_res: MOV r_dl,BL ; número de unidades
MOV r_ch,AH ; mayor número de cilindro
MOV r_cl,AL ; mayor número de sector
MOV r_bl,DH ; tipo de la unidad
MOV r_bh,0
MOV r_es,ES ; ES:DI para la salida
MOV r_di,DI
XOR AX,AX
MOV DS:[41h],AH ; resultado correcto
MOV r_al,AL
JMP main_exit
gdrv_res_null: XOR DI,DI ; devolver todo a 0
gdrv_half_res: XOR DH,DH
XOR AX,AX
MOV ES,AX
MOV r_dh,0
MOV BX,DI
XOR DI,DI
JMP gdrv_set_res ; resultado trivial
gdrv_eval: MOV BX,DI
OR SI,SI
JZ gdrv_res_null ; no existe la unidad
CMP SI,3
JBE gdrv_calc_p ; es de 5¼
XOR SI,SI
JMP gdrv_res_null
get_drv_param ENDP
; ------------ Función 18h: Establecer densidad de formateo.
set_media_fmt PROC
CMP DL,1
JBE setm_do
MOV AH,1 ; función/parámetro incorrecto
setm_exit_err: STC
JMP main_exit
setm_do: CALL get_drive_type ; obtener tipo disquetera en AL
JZ setm_drv_ok
setm_drv_unkn: MOV AH,0Ch ; tipo de unidad desconocido
JMP setm_exit_err
setm_drv_ok: XOR AH,AH
MOV DI,AX ; tipo de unidad
MOV DL,r_dl
MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico unidad
CMP AL,1 ; ¿360K?
JNE setm_not360
MOV CX,r_cx ; restaurar CX
CMP CX,2709h ; ¿40 pistas 9 sectores?
LEA SI,t360in360
JNZ setm_drv_unkn ; sólo se permite ese formato
JMP setm_360in360
setm_not360: CMP AL,3 ; ¿720K?
JNE setm_not720
MOV CX,r_cx ; restaurar CX
CMP CX,4F09h ; ¿80 pistas 9 sectores?
JNE setm_drv_unkn ; sólo se permite ese formato
JMP setm_setm
setm_not720: CMP AL,4 ; ¿1.44M?
JE setm_1440
CMP AL,2 ; ¿1.2M?
JE setm_1200
CMP AL,5 ; ¿2.88M?
JNE setm_drv_unkn
MOV CX,r_cx ; 2.88M: restaurar CX
CMP CX,4F24h ; ¿80 pistas 36 sectores?
JE setm_setm ; correcto
CMP CX,4F12h ; ¿80 pistas 18 sectores?
JE setm_setm ; correcto
CMP CX,4F09h ; ¿80 pistas 9 sectores?
JE setm_setm ; correcto
JMP setm_drv_unkn ; permitir sólo esos formatos
setm_1200: MOV CX,r_cx ; restaurar CX
CMP CX,4F0Fh ; ¿80 pistas 15 sectores?
JE setm_setm ; correcto
CMP CX,2709h ; ¿80 pistas 9 sectores?
JNE setm_drv_unkn ; permitir sólo esos formatos
JMP setm_setm ; correcto
setm_1440: MOV CX,r_cx ; restaurar CX
CMP CX,4F12h ; ¿80 pistas 18 sectores?
JE setm_setm ; correcto
CMP CX,4F09h ; ¿80 pistas 9 sectores?
JNE setm_drv_unkn ; permitir sólo esos formatos
setm_setm: MOV CX,r_cx ; restaurar CX
CMP CX,4F12h ; ¿80 pistas 18 sectores?
MOV AL,17h ; su byte de medio físico
LEA SI,t1440 ; es 1.44M
MOV DH,0 ; 500 Kbps
JZ setm_m_ok
CMP CX,4F09h ; ¿80 pistas 9 sectores?
MOV AL,97h ; su byte de medio físico
LEA SI,t720 ; es 720K
MOV DH,2 ; 250 Kbps
JZ setm_m_ok
CMP CX,4F0Fh ; ¿80 pistas 15 sectores?
MOV AL,15h ; su byte de medio físico
LEA SI,t1200 ; es 1.2M
MOV DH,0 ; 500 Kbps
JZ setm_m_ok
CMP CX,4F24h ; ¿80 pistas 36 sectores?
MOV AL,0D7h ; su byte de medio físico
LEA SI,t2880 ; es 2.88M
MOV DH,3 ; 1 Mbps
JZ setm_m_ok
MOV AL,74h ; byte medio físico 360K en 1.2
LEA SI,t360en1200 ; es 360K en 1.2M
MOV DH,1 ; 300 Kbps
setm_m_ok: MOV [BX],AL ; establecer medio físico
PUSH DX
CALL set_rate ; velocidad de transferencia DH
POP DX
MOV AL,[BX]
AND AL,0C0h
AND BYTE PTR DS:[8Bh],3Fh ; borrar bits de velocidad
OR BYTE PTR DS:[8Bh],AL ; nueva velocidad
MOV r_di,SI
MOV r_es,CS ; retornar tabla parámetros
MOV BYTE PTR DS:[41h],0 ; no hay error
XOR AH,AH
JMP main_exit
setm_360in360: MOV DH,2 ; 250 Kbps
MOV AL,93h ; 360K en 360K
JMP setm_m_ok
set_media_fmt ENDP
; ------------ Recalibrar.
recalibrate PROC
PUSH SI
PUSH CX
PUSH DX
MOV DH,DL
MOV DL,7 ; comando "recalibrate"
MOV SI,DX
MOV CH,2 ; comando de 2 bytes
AND BYTE PTR DS:[3Eh],7Fh ; con espera de IRQ
CALL exec_cmd
JC recal_end ; fallo
MOV SI,8 ; "leer estado interrupciones"
MOV CH,1 ; comando de 1 byte
OR BYTE PTR DS:[3Eh],80h ; sin espera de IRQ
CALL exec_cmd
JC recal_end ; fallo
MOV BX,42h
MOV CX,2 ; 2 bytes de resultado
CALL get_results ; almacenar resultado
JC recal_end ; fallo
MOV BX,42h
MOV AH,40h
MOV DL,[BX] ; ST0
AND DL,60h
CMP DL,60h ; ¿terminación anormal y
STC ; seek-end?
JE recal_end ; fallo
POP DX
PUSH DX
XOR DH,DH
MOV BX,94H
ADD BX,DX
MOV BYTE PTR DS:[BX],0 ; cilindro en curso = 0
MOV CL,DL
MOV DL,1
SHL DL,CL
OR DS:[3Eh],DL ; unidad recalibrada
MOV CX,43h
CALL wait_time ; retardo de 1 ms
XOR AH,AH
recal_end: MOV DS:[41h],AH ; código de error / acierto
POP DX
POP CX
POP SI
RET
recalibrate ENDP
; ------------ Llevar el cabezal al cilindro adecuado.
seek PROC
PUSH BX
PUSH CX
MOV AH,DS:[3Eh] ; estado de recalibración
MOV CL,DL
INC CL
SHR AH,CL
JC seek_only
CALL recalibrate ; hay que recalibrar
JNC seek_only
CALL recalibrate ; segundo intento
JNC seek_only
JMP seek_exit
seek_only: MOV BX,94H
XOR DH,DH
ADD BX,DX ; [BX] -> cilindro actual
MOV SI,90h
ADD SI,DX ; [SI] -> estado físico unidad
MOV DL,CH
TEST BYTE PTR DS:[SI],20h ; ¿hacer double stepping?
JZ seek_cil_ok1
ADD DL,DL ; sí: cilindro=cilindro*2
seek_cil_ok1: CMP [BX],DL ; ¿ya estamos en ese cilindro?
MOV DX,r_dx
JNE seek_do ; aún no
CMP BYTE PTR DS:[41h],40h ; ¿hubo "seek error"?
JE seek_do
XOR AH,AH ; no, seek innecesario
JMP seek_exit
seek_do: SHL DH,2
OR DH,DL ; byte 1 del comando seek
MOV DL,0FH ; orden seek
MOV SI,DX
MOV CL,CH ; cilindro
MOV DX,r_dx ; unidad / cabezal
MOV BX,90h
XOR DH,DH
ADD BX,DX ; [BX] -> estado físico
TEST BYTE PTR DS:[BX],20h ; ¿hacer double stepping?
JZ seek_cil_ok2 ; no
ADD CL,CL ; sí: cilindro=cilindro*2
seek_cil_ok2: MOV DI,CX
MOV CH,3 ; comando de 3 bytes
AND BYTE PTR DS:[3Eh],7Fh ; hay que esperar IRQ
CALL exec_cmd
JNC seek_ok ; seek correcto
JMP seek_result
seek_ok: MOV SI,8 ; "leer estado interrupciones"
MOV CH,1 ; comando de 1 byte
OR BYTE PTR DS:[3Eh],80h ; no hay que esperar IRQ
CALL exec_cmd
JC seek_result ; fallo
MOV BX,42h
MOV CX,2
CALL get_results ; leer bytes de resultados
JC seek_result
MOV BX,42h
MOV AH,40h ; "seek error"
MOV DL,[BX] ; ST0
AND DL,60h
CMP DL,60h ; comprobarlo
STC
JE seek_result ; terminación brusca
MOV DX,r_dx ; restaurar DX
POP CX
PUSH CX ; restaurar CX
MOV SI,94H
XOR DH,DH
ADD SI,DX
MOV [SI],CH ; actualizar cilindro actual
MOV BX,90h
ADD BX,DX ; [BX] -> estado físico unidad
MOV BL,[BX]
TEST BL,20h ; ¿double stepping?
JZ seek_cil_ok3
ADD [SI],CH ; pues cilindro*2
seek_cil_ok3: PUSH DS
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AL,[SI+9] ; tiempo estabilización cabezal
POP DS
TEST BYTE PTR DS:[3Fh],80h ; ¿operación en curso?
JZ seek_wait ; es lectura o verificación
OR AL,AL
JNZ seek_wait ; escritura, cte != 0
CMP BL,17h
MOV AL,0Fh
JE seek_wait ; 15 ms excepto para 360K
AND BL,7
MOV AL,14h
JZ seek_wait ; 20 ms para unidades de 360K
CMP BL,3
JE seek_wait ; 20 ms para unidades de 360K
MOV AL,0Fh ; 15 ms para demás unidades
seek_wait: OR AL,AL
JZ seek_wait_end
MOV CX,43h
CALL wait_time ; esperar 1 ms...
DEC AL
JMP seek_wait ; ...durante AL veces
seek_wait_end: XOR AH,AH
seek_result: MOV DS:[41h],AH ; resultado
seek_exit: MOV DX,r_dx ; restaurar DX
POP CX
POP BX
RET
seek ENDP
; ------------ Ejecutar operación de E/S a través del FDC.
perform_io PROC
CALL seek
JNC p_io
p_io_dsk_err: MOV AL,0 ; fallo
PUSH AX
MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
POP AX
JMP p_io_exit
p_io: PUSH DS ; preparar bytes comando R/W
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AX,[SI+2]
AND AX,0FF00h ; AH = bytes por sector
MOV AL,CL ; AL = primer sector
MOV [BP],AX
MOV BX,[SI+4] ; BL=sectores/pista, BH=GAP R/W
MOV CL,[SI+6] ; CL=longitud de sector (tam=0)
POP DS
MOV SI,90h
XOR DH,DH
ADD SI,DX ; nº sector/tamaño (bytes 4-5)
MOV DL,[SI] ; estado físico de la unidad
AND DL,7
MOV DH,1Bh ; GAP R/W para 1.2M/1.44M/2.88M
CMP DL,5
JE p_io_gap_ok ; 1.2M en 1.2M
CMP BYTE PTR DS:[SI],17h
JE p_io_gap_ok ; 1.44M
CMP BYTE PTR DS:[SI],0D7h
JE p_io_gap_ok ; 2.88M
MOV DH,23h ; GAP R/W para 360K en 1.2M
CMP DL,4
JE p_io_gap_ok ; 360K en 1.2M
MOV DH,2Ah ; GAP R/W para demás casos
p_io_gap_ok: MOV BH,DH ; BX=numsect/GAP (bytes 6-7)
MOV DX,r_dx ; restaurar DX
PUSH CX
MOV CL,CH ; cilindro
MOV CH,DH ; cabezal
MOV DI,CX ; cabezal/cilindro (bytes 2-3)
SHL DH,2
OR DH,DL ; byte 1 de comando FDC
MOV DL,0E6h ; comando leer datos
MOV AX,r_ax ; orden
CMP AH,3 ; ¿write?
JNE p_io_orden_ok
MOV DL,0C5h ; comando escribir datos
p_io_orden_ok: MOV SI,DX ; (bytes 0-1 de la orden)
POP CX
MOV CH,9
AND BYTE PTR DS:[3Eh],7Fh ; esperar interrupción
CALL exec_cmd
JNC p_io_dsk_ok
JMP p_io_dsk_err ; fallo
p_io_dsk_ok: MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
JNC p_io_res_ok
MOV AL,0
JMP p_io_exit ; fallo: respetar código error
p_io_res_ok: CALL get_bios_err
p_io_exit: MOV DS:[41h],AH
MOV DX,r_dx ; restaurar registros
MOV BX,r_bx
MOV CX,r_cx
JMP io_performed ; continuar operación E/S
perform_io ENDP
; ------------ Arrancar motor si no lo está.
motor_on PROC
PUSH DX
PUSH CX
CLI ; * evitar reentrada
MOV BYTE PTR DS:[40h],0FFh ; evitar detención motor
AND BYTE PTR DS:[3Fh],0CFh ; a 0 bits de disquetera
MOV CH,DL
SHL DL,4
OR DS:[3Fh],DL ; nueva disquetera seleccionada
MOV CL,CH
MOV DL,DS:[3Fh] ; estado de motores
INC CL
SHR DL,CL
JC motor_is_on ; motor ya en marcha
MOV DL,1
DEC CL
SHL DL,CL
OR DS:[3Fh],DL ; señalizar que está en marcha
STI ; * fin de la fase crítica
MOV AL,DS:[3Fh] ; estado de motores
ROR AL,4
OR AL,0CH ; no resetear, modo DMA
MOV DX,3F2h
OUT DX,AL ; registro salida digital
MOV AX,90FDh
INT 15h ; permitir multitarea
JC motor_on_end
MOV AH,DS:[3Fh]
PUSH DS
PUSH SI
XOR SI,SI
MOV DS,SI
LDS SI,DWORD PTR DS:[78h] ; DS:SI -> INT 1Eh
MOV AL,[SI+0Ah]
POP SI ; AL = tiempo aceleración motor
POP DS ; en octavos de segundo
SHL AH,1
JNC motor_on_rv ; operación read/verify
CMP AL,8
JAE motor_on_wait
MOV AL,8
JMP motor_on_wait ; escritura: al menos 1 segundo
motor_on_rv: CMP AL,5
JAE motor_on_wait
MOV AL,5 ; read/verify: al menos 625 ms
motor_on_wait: MOV CX,208EH
CALL wait_time ; retardo de unos 125 ms
DEC AL
JNZ motor_on_wait ; completar retardo
JMP motor_on_end
motor_is_on: STI
MOV AL,DS:[3Fh] ; estado de motores
ROR AL,4
OR AL,0CH ; no resetear, modo DMA
MOV DX,3F2h
OUT DX,AL ; seleccionar unidad
motor_on_end: POP CX
POP DX
RET
motor_on ENDP
; ------------ Asignar cuenta para detención motor y devolver en BL
; y AL el próximo número de sector a transferir.
end_io_access PROC
PUSH AX
PUSH DS
XOR BX,BX
MOV DS,BX
LDS BX,DWORD PTR DS:[78h] ; DS:BX -> INT 1Eh
MOV AH,[BX+2] ; tics hasta detención motor
MOV AL,[BX+4]
INC AL ; sectores/pista + 1
POP DS
MOV BX,42h
CMP CH,[BX+3] ; ¿mismo cilindro resultante?
JNE end_io_exit
CMP DH,[BX+4] ; ¿mismo cabezal resultante?
JNE end_io_exit
MOV AL,[BX+5] ; número de sector resultante
end_io_exit: MOV DS:[40h],AH ; tiempo para detención motor
MOV BL,AL ; último nº sector transferido
POP AX
RET
end_io_access ENDP
; ------------ Leer la línea de cambio de disco y bajarla si está
; activa.
read_disk_chg PROC
PUSH CX
CALL get_drive_type ; obtener tipo disquetera en AL
MOV AH,0
JNZ fallo_cmos
DEC AL
JZ rdchg_set_cod ; evitar test en 360K
fallo_cmos: MOV AL,[SI] ; estado físico de la unidad
AND AL,7
JZ rdchg_set_cod ; evitar test en 360K
CMP AL,3
JE rdchg_set_cod ; evitar test en 360K
MOV DX,3F7h ; registro de entrada digital
IN AL,DX ; leer línea de cambio de disco
SHL AL,1
JNC rdchg_exit ; no hay cambio de disco
AND BYTE PTR DS:[SI],0EFH ; medio no determinado
CALL full_init ; inicialización plena
JC rdchg_exit ; fallo
MOV DX,r_dx ; restaurar DX
MOV CH,1
CALL seek ; cabezal a cilindro 1
JC rdchg_exit
MOV CH,0
CALL seek ; cabezal a cilindro 0
JC rdchg_exit
MOV AH,6 ; error "disk changed"
MOV DX,3F7h
IN AL,DX ; leer línea de cambio de disco
SHL AL,1
JNC rdchg_set_cod ; se ha podido bajar
MOV AH,80h ; no se pudo: no hay disquete
rdchg_set_cod: OR AH,AH
JZ rdchg_exit
STC
rdchg_exit: MOV DX,r_dx ; restaurar DX
POP CX
RET
read_disk_chg ENDP
; ------------ Programar el DMA para efectuar la E/S.
set_dma PROC
PUSH AX
PUSH DX
CLI
MOV AL,AH
OUT 0CH,AL ; clear first/last flip-flop
JCXZ $+2 ; retardo para E/S
JCXZ $+2
OUT 0BH,AL ; registro de modo del DMA
JCXZ $+2
JCXZ $+2
MOV AL,CL
OUT 5,AL
JCXZ $+2
JCXZ $+2
MOV AL,CH
OUT 5,AL ; enviada cuenta de bytes
JCXZ $+2
JCXZ $+2
MOV AL,BL
OUT 4,AL
JCXZ $+2
JCXZ $+2
MOV AL,BH
OUT 4,AL ; enviada dirección base
JCXZ $+2
JCXZ $+2
MOV AX,ES
OUT 81H,AL ; registro de página canal 2
JCXZ $+2
JCXZ $+2
MOV AL,2
OUT 0AH,AL ; habilitar canal 2 del DMA
STI
POP DX
POP AX
RET
set_dma ENDP
; ------------ Calcular parámetros para programar el DMA.
eval_dir_DMA PROC
PUSH CX
XOR AX,AX
MOV CX,ES ; segmento ES
SHL CX,1 ; desplazar...
RCL AL,1
SHL CX,1
RCL AL,1
SHL CX,1
RCL AL,1
SHL CX,1
RCL AL,1 ; ... AL:CX >> 4
MOV BX,r_bx ; offset BX
ADD BX,CX
ADC AX,0 ; AX:BX dirección física 20 bit
MOV ES,AX ; página de DMA
POP CX
MOV AX,CX
ADD AX,BX
JNC eval_dma_ret ; no cruza frontera de 64k
MOV AH,9 ; "DMA across 64k boundary"
eval_dma_ret: RET
eval_dir_DMA ENDP
; ------------ Enviar comando completo al FDC de CH bytes, contenido
; en SI, DI, [BP], BX y CL (parte baja - alta).
send_full_cmd PROC
MOV AX,SI
MOV AH,AL
CALL fdc_write ; enviar SI-L
DEC CH
JBE send_full_ret ; acabado (ZF=1) ó error (CF=1)
MOV AX,SI
CALL fdc_write ; enviar SI-H
DEC CH
JBE send_full_ret
MOV AX,DI
MOV AH,AL
CALL fdc_write ; enviar DI-L
DEC CH
JBE send_full_ret
MOV AX,DI
CALL fdc_write ; enviar DI-H
DEC CH
JBE send_full_ret
MOV AX,[BP]
MOV AH,AL
CALL fdc_write ; enviar [BP]-L
DEC CH
JBE send_full_ret
MOV AX,[BP]
CALL fdc_write ; enviar [BP]-H
DEC CH
JBE send_full_ret
MOV AH,BL
CALL fdc_write ; enviar BL
DEC CH
JBE send_full_ret
MOV AH,BH
CALL fdc_write ; enviar BH
DEC CH
JBE send_full_ret
MOV AH,CL
CALL fdc_write ; enviar CL
send_full_ret: RET
send_full_cmd ENDP
; ------------ Enviar comando al FDC con/sin espera de interrupción.
exec_cmd PROC
TEST BYTE PTR DS:[3Eh],80h ; ¿hay que esperar IRQ?
JZ exec_cmd_irq ; sí
AND BYTE PTR DS:[3Eh],7Fh ; no: devolver a 0 bit IRQ
CALL send_full_cmd ; enviar comando
RET
exec_cmd_irq: CALL send_full_cmd ; enviar comando
JC exec_cmd_ret
MOV AX,9001h
INT 15h ; permitir multitarea
STI
JC exec_cmd_err
CALL wait_int ; esperar IRQ
JNC exec_cmd_ok
exec_cmd_err: MOV AH,80h ; "not ready" (AH=80h)
exec_cmd_ret: RET
exec_cmd_ok: AND BYTE PTR DS:[3Eh],7Fh ; bit IRQ listo para otra
XOR AH,AH ; éxito
RET
exec_cmd ENDP
; ------------ Enviar byte al FDC.
fdc_write PROC
PUSH CX
PUSH DX
MOV CX,2
CALL wait_time ; esperar 15-30 µs
MOV DX,3F4h ; registro de estado
PUSH AX
MOV AH,40h
XOR CX,CX
CALL wait0 ; esperar FDC listo para OUT
JC fdc_wr_fail
MOV AH,80h
XOR CX,CX
CALL wait1
JC fdc_wr_fail ; error
POP AX
MOV DX,3F5h ; registro de datos
MOV AL,AH
OUT DX,AL ; escribir el byte
JMP fdc_wr_ret
fdc_wr_fail: POP AX
MOV AH,80h ; error "not ready"
fdc_wr_ret: POP DX
POP CX
RET
fdc_write ENDP
; ------------ Leer del FDC CX bytes de resultado en [BX++].
get_results PROC
PUSH DX
get_one_byte: PUSH CX
CALL fdc_read
POP CX
JC get_res_ret ; no hay más bytes que leer
MOV [BX],AL
INC BX
LOOP get_one_byte ; leer todos los bytes
MOV CX,4
CALL wait_time ; esperar 45-60 µs
MOV DX,3F4h
IN AL,DX ; leer registro de estado
TEST AL,10h
JZ get_res_ok ; el FDC no está ocupado
MOV AH,20h
STC ; lo estaba: "bad NEC"
JMP get_res_ret
get_res_ok: XOR AH,AH ; operación correcta
get_res_ret: POP DX
RET
get_results ENDP
; ------------ Leer byte del FDC.
fdc_read PROC
PUSH DX
MOV CX,3
CALL wait_time ; esperar 30-45 µs
MOV DX,3F4h ; registro de estado
MOV AH,80h
XOR CX,CX
CALL wait1 ; esperar FDC listo para E/S
MOV AH,80h
JC fdc_read_end ; error "not ready" (AH=80h)
IN AL,DX
TEST AL,40h ; ¿el FDC quiere dar un byte?
JNZ fdc_read_ok
MOV AH,20H ; no: error "bad NEC" (AH=20h)
STC
JMP fdc_read_end
fdc_read_ok: JCXZ $+2 ; retardo para E/S
JCXZ $+2
MOV DX,3F5h ; registro de datos
IN AL,DX ; leer el byte
fdc_read_end: POP DX
RET
fdc_read ENDP
; ------------ Obtener código de error de la BIOS.
get_bios_err PROC
MOV BX,42h ; área de resultados del FDC
MOV BX,[BX]
TEST BL,0C0h ; ¿que tal ST0?
MOV AH,0
JZ bios_err_det ; ¡perfecto!
TEST BL,40h ; ¿terminación brusca/anormal?
MOV AH,20H ; "bad NEC"
JZ bios_err_det
TEST BH,1 ; ¿falta marca de direcciones?
MOV AH,2 ; "address mark not found"
JNZ bios_err_det
TEST BH,2 ; ¿protegido contra escritura?
MOV AH,3 ; "write-protect error"
JNZ bios_err_det
TEST BH,4 ; ¿sector no encontrado?
MOV AH,4 ; "sector not found"
JNZ bios_err_det
TEST BH,10H ; ¿DMA no atendido a tiempo?
MOV AH,8 ; "DMA overrun"
JNZ bios_err_det
TEST BH,20H ; ¿falla el CRC?
MOV AH,10H ; "CRC error"
JNZ bios_err_det
TEST BH,80h ; ¿acceso fuera de la pista?
MOV AH,4 ; "sector not found"
JNZ bios_err_det
MOV AH,20H ; otro error: "bad NEC"
bios_err_det: RET
get_bios_err ENDP
; ------------ Reinicializar la controladora de disquetes.
init_fdc PROC
CALL reset_disk ; resetear FDC
JC init_fin ; fallo al resetear
MOV DX,3F4h ; registro de estado del FDC
IN AL,DX
TEST AL,80h
JZ init_otravez ; el FDC no está listo
TEST AL,40h
JZ init_bien ; el FDC espera datos de la CPU
init_otravez: CALL reset_disk ; otro intento más
MOV DX,3F4h
IN AL,DX
TEST AL,80h
JZ init_mal ; nada, que no tira
TEST AL,40h
JZ init_bien ; bueno, ya despierta
init_mal: MOV AH,20h ; fallo de la controladora
STC
JMP init_fin
init_bien: MOV AH,8 ; "leer estado interrupciones"
CALL fdc_write ; enviar comando
JC init_fin ; fallo
CALL fdc_read ; leer ST0
JC init_fin ; fallo
MOV DS:[42h],AL ; guardar ST0
PUSH AX
CALL fdc_read ; leer cilindro actual
MOV DS:[42h+1],AL ; guardarlo
POP CX
JC init_fin ; fallo
AND CL,0C0h
CMP CL,0C0h ; ¿terminación anormal?
JNE init_mal ; no es terminación anormal
XOR AH,AH ; ok: el FDC detecta el fallo
init_fin: JMP fdc_init
init_fdc ENDP
; ------------ Resetear el FDC.
reset_disk PROC
CLI
AND BYTE PTR DS:[3Fh],7Fh ; operación R/V
AND BYTE PTR DS:[3Eh],7Fh ; borrar bit IRQ
MOV AL,DS:[3Fh]
ROL AL,4 ; bits 7-4: motores
AND AL,0FBH ; bits 3-0: unidad
OR AL,8 ; interrupciones ON + reset
MOV DX,3F2h
OUT DX,AL ; hacer reset
MOV CX,3
CALL wait_time ; retardo de 30-45µs
OR AL,0CH
OUT DX,AL ; fin del reset
MOV AX,9001h
INT 15h ; facilitar multitarea
STI
JC fin_wait ; error
CALL wait_int ; esperar interrupción de disco
fin_wait: MOV AH,80h ; "unidad no preparada"
JC exit_reset ; hay error
AND BYTE PTR DS:[3Eh],7Fh ; borrar bit IRQ
XOR AH,AH ; no hay error
exit_reset: RET
reset_disk ENDP
; ------------ Enviar comando specify obtenido de INT 1Eh al FDC.
send_specify PROC
PUSH DS
XOR BX,BX
MOV DS,BX
LDS BX,DWORD PTR DS:[78h] ; DS:BX -> INT 1Eh
MOV AL,3 ; comando specify del FDC
MOV AH,[BX] ; byte 0 del comando specify
MOV SI,AX
MOV AL,[BX+1] ; byte 1 del comando specify
MOV DI,AX
MOV CH,3 ; orden de 3 bytes (SI, DI-L)
POP DS
OR BYTE PTR DS:[3Eh],80h ; no esperar IRQ
CALL exec_cmd ; mandar specify al FDC
JMP specify_sent
send_specify ENDP
; ------------ Esperar una interrupción de disco durante 2 segundos.
wait_int PROC
MOV BX,3Eh ; variable con flag de INT
XOR CX,CX
CALL wait_event ; esperar IRQ durante 1 segundo
JNC wait_int_ret
XOR CX,CX
CALL wait_event ; esperar otro segundo más
wait_int_ret: RET
wait_int ENDP
; ------------ Devolver en AL el tipo de la unidad DL.
get_drive_type PROC
CALL peek_cmos ; leer tipo de disqueteras
OR DL,DL
JNZ gdt_unidad_ok
SHR AL,4 ; unidad A:
gdt_unidad_ok: AND AL,0Fh
CMP SP,SP ; ZF=1 -> resultado correcto
RET
get_drive_type ENDP
; ------------ Determinar la densidad del disquete.
detect_media PROC
PUSH DX
PUSH CX
PUSH BX
MOV BL,r_dl
XOR BH,BH
MOV DL,BL
CALL get_drive_type ; obtener tipo disquetera en AL
MOV AH,0
JZ dm_fast ; ha sido posible obtenerlo
JMP dm_slow ; usar procedimiento lento
dm_fast: MOV BYTE PTR DS:[BX+90h],0 ; estado físico unidad
DEC AX
JNZ dm_es_1200K?
MOV AL,93h ; 360K: 360K en 360K, 250 Kbps
dm_try: PUSH AX
MOV DH,AL
AND DH,0C0h
SHR DH,6
CALL set_rate ; velocidad de transferencia DH
POP AX
dm_result: MOV DS:[BX+90h],AL ; estado físico...
TEST AL,10h ; ...¿determinado?
JZ dm_fails ; aún no
XOR AH,AH
JMP dm_exit ; sí: resultado correcto
NOP
dm_es_1200K?: DEC AX
JNZ dm_es_720K?
MOV AL,0
CALL read_ids ; 1.2M: 500 kbps
MOV AL,15h ; indicar 1.2M en 1.2M
JNC dm_result ; sí funciona
MOV AL,40h
MOV BYTE PTR DS:[BX+90h],2
CALL read_ids ; probar 300 Kbps
MOV AL,74h ; indicar 360K en 1.2M
JNC dm_result ; sí funciona
MOV AL,2 ; indicar "¿1.2M en 1.2M?"
JMP dm_result
dm_es_720K?: DEC AX
JNZ dm_es_1440K?
MOV AL,97h ; 720K: 250 Kbps
JMP dm_try ; a probar suerte
dm_es_1440K?: DEC AX
JNZ dm_es_2880K
MOV AL,0
CALL read_ids ; 1.44M: 500 Kbps
MOV AL,17h ; indicar 1.44M
JNC dm_result ; sí funciona
MOV AL,80h
CALL read_ids ; probar a 250 Kbps
MOV AL,97h ; indicar 720K
JNC dm_result ; sí funciona
MOV AL,7 ; indicar "¿1.44M?"
JMP dm_result
dm_es_2880K: MOV AL,0C0h
CALL read_ids ; 2.88M: 1 Mbps
MOV AL,0D7h ; indicar 2.88M en 2.88M
JNC dm_result ; sí funciona
MOV AL,0
CALL read_ids ; probar 500 Kbps
MOV AL,17h ; indicar 1.44M
JNC dm_result ; sí funciona
MOV AL,80h
CALL read_ids ; probar 250 Kbps
MOV AL,97h ; indicar 720K
JNC dm_result ; sí funciona
MOV AL,0C7h ; indicar "¿2.88M en 2.88M?"
JMP dm_result
dm_fails: STC ; condición de error
dm_exit: MOV DS:[41h],AH ; código de error
POP BX
POP CX
POP DX
RET
dm_slow: MOV AL,0
CALL read_ids ; probar 500 Kbps
MOV AL,15h ; indicar 1.2M en 1.2M
JNC dm_slow_ok ; sí funciona
MOV AL,40h
MOV BYTE PTR DS:[BX+90h],2
CALL read_ids ; probar 300 Kbps
MOV AL,74h ; indicar 360K en 1.2M
JNC dm_slow_ok ; sí funciona
MOV AL,80h
CALL read_ids ; probar 250 Kbps
MOV AL,97h ; indicar 720K ó 360K en 360K
JNC dm_slow_ok ; sí funciona
MOV AL,0C0h
CALL read_ids ; probar 1 Mbps
MOV AL,0D7h ; indicar 2.88M en 2.88M
JC dm_fails ; no funciona
dm_slow_ok: JMP dm_result
detect_media ENDP
; ------------ Efectuar una lectura de ID's a velocidad AL (bits 6-7).
read_ids PROC
PUSH BX
PUSHF
CLI
MOV BYTE PTR DS:[40h],0FFh ; evitar detención motor
POPF
SHR AL,6 ; colocar bits de velocidad
MOV DH,AL
CALL set_rate ; velocidad de transferencia DH
MOV DL,r_dl
CALL recalibrate ; recalibrar
JNC read_id_try
CALL recalibrate ; segundo intento
JC read_id_err
read_id_try: MOV CX,3 ; 3 intentos
read_id_retry: PUSH CX
MOV DH,DL ; en el cabezal 0 de la unidad
MOV DL,4Ah ; comando de leer ID's
MOV SI,DX
MOV DL,DH
MOV CH,2 ; comando de 2 bytes
AND BYTE PTR DS:[3Eh],7Fh ; esperar interrupción
CALL exec_cmd
JC read_id_fails ; fallo
MOV BX,42h
MOV CX,7
CALL get_results ; leer bytes de resultados
JC read_id_fails
CALL get_bios_err ; obtener código de error
POP CX
OR AH,AH
JZ read_id_ret ; ya no hay fallo
LOOP read_id_retry ; reintentar
JMP read_id_err ; mala suerte
read_id_fails: POP CX
read_id_err: STC
read_id_ret: POP BX
RET
read_ids ENDP
; ------------ Seleccionar la velocidad de transferencia adecuada.
select_rate PROC
PUSH SI
MOV SI,90h
XOR DH,DH
ADD SI,DX ; [SI] -> estado físico unidad
MOV DH,[SI] ; estado físico nueva unidad
MOV DL,DS:[8Bh] ; control del medio físico
AND DX,0C0C0h ; aislar bits de velocidad
CMP DL,DH ; ¿velocidad ya seleccionada?
JE selected_rate
AND BYTE PTR DS:[8Bh],3Fh ; no: borrar la anterior
OR DS:[8Bh],DH ; indicar la nueva
AND DH,0C0h
ROL DH,2
CALL set_rate ; nueva velocidad transferencia
selected_rate: POP SI
MOV DX,r_dx ; restaurar DX
RET
select_rate ENDP
; ------------ Establecer la velocidad de transferencia DH.
set_rate PROC
PUSH AX
MOV AL,DH
MOV DX,3F7h ; registro de control del disquete
OUT DX,AL ; seleccionar velocidad
POP AX
RET
set_rate ENDP
; ------------ Esperar que alguno de los bits a 1 de AH en el
; puerto DX se pongan a 0 en no más de CX 15.09 µs.
wait0 PROC
PUSH AX
wait0_do: IN AL,DX ; leer del puerto E/S
TEST AL,AH
JZ wait0_end ; bit(s) ya a 0
wait0_delay0: IN AL,61h
TEST AL,10h
JZ wait0_delay0 ; esperar 15.09 µs
DEC CX
JZ wait0_fail ; timeout
IN AL,DX ; volver a leer del puerto E/S
TEST AL,AH
JZ wait0_end ; bit(s) ya a 0
wait0_delay1: IN AL,61h
TEST AL,10h
JNZ wait0_delay1 ; esperar 15.09 µs
DEC CX
JNZ wait0_do ; aún no hay timeout
wait0_fail: STC ; error de timeout
wait0_end: POP AX
RET
wait0 ENDP
; ------------ Esperar que alguno de los bits a 1 de AH en el
; puerto DX se pongan a 1 en no más de CX 15.09 µs.
wait1 PROC
PUSH AX
wait1_do: IN AL,DX ; leer del puerto E/S
TEST AL,AH
JNZ wait1_end ; bit(s) ya a 1
wait1_delay0: IN AL,61h
TEST AL,10h
JZ wait1_delay0 ; esperar 15.09 µs
DEC CX
JZ wait1_fail ; timeout
IN AL,DX ; volver a leer del puerto E/S
TEST AL,AH
JNZ wait1_end ; bit(s) ya a 1
wait1_delay1: IN AL,61h
TEST AL,10h
JNZ wait1_delay1 ; esperar 15.09 µs
DEC CX
JNZ wait1_do ; aún no hay timeout
wait1_fail: STC ; error de timeout
wait1_end: POP AX
RET
wait1 ENDP
; ------------ Esperar evento durante CX 15.09 µs.
wait_event PROC
PUSH AX
test_int: TEST BYTE PTR [BX],80h
JNZ fin_w_event ; llegó la interrupción
w_ref1: IN AL,61h
TEST AL,10h
JZ w_ref1 ; esperar 15 µs
DEC CX
JZ w_event_none ; timeout
TEST BYTE PTR [BX],80h
JNZ fin_w_event ; llegó la interrupción
w_ref2: IN AL,61h
TEST AL,10h
JNZ w_ref2 ; esperar 15 µs
DEC CX
JNZ test_int ; queda tiempo, esperar más
w_event_none: STC ; no llegó la interrupción
fin_w_event: POP AX
RET
wait_event ENDP
; ------------ Retardo de CX 15.09 µs aproximadamente.
wait_time PROC
PUSH AX
wait_ref_h: IN AL,61h
TEST AL,10h ; esperar ciclo de refresco
JZ wait_ref_h ; de memoria (15,09 µs)
DEC CX
JZ wait_time_fin ; fin de la espera
wait_ref_l: IN AL,61h
TEST AL,10h ; esperar ciclo de refresco
JNZ wait_ref_l ; de memoria (15,09 µs)
DEC CX
JNZ wait_ref_h ; completar espera
wait_time_fin: POP AX
RET
wait_time ENDP
; ------------ Simular la lectura del registro 10h de la CMOS, para
; el tipo de las disqueteras.
peek_cmos PROC
MOV AL,CS:tipo_drvs ; nuestro tipo simulado
RET
peek_cmos ENDP
; ------------ Datos.
tipo_drvs DB 0 ; tipo de disqueteras (definido al instalar)
; --- Tabla de saltos a las funciones
tab_jmp DW reset, get_status
DW read_wr_verify, read_wr_verify, read_wr_verify
DW format_track, get_drv_param, get_disk_type
DW detect_change, set_type_fmt, set_media_fmt
; --- Tabla de tamaños en sectores y cilindros
tab_disksize DW 9 + 39 * 256 ; 360K
DW 15 + 79 * 256 ; 1.2M
DW 9 + 79 * 256 ; 720K
DW 18 + 79 * 256 ; 1.44M
DW 36 + 79 * 256 ; 2.88M
; --- Tablas de parámetros de disco (sintaxis INT 1Eh)
tab_ptr_1e DW t360in360, t1200, t720, t1440, t2880
; Bytes de esta tabla, similar a la de INT 1Eh:
;
; 0) byte 1 para 'Specify' (step rate-head unload)
; 1) byte 2 para 'Specify' (head load-modo DMA)
; 2) tics de reloj hasta detención del motor
; 3) tamaño de sector (0-128, 1-256, 2-512, ...)
; 4) sectores por pista
; 5) GAP3 para lectura/escritura
; 6) longitud concreta de sector si tamaño=0
; 7) GAP3 para formateo
; 8) byte de relleno al formatear
; 9) tiempo de estabilización del cabezal en ms
; 10) tiempo aceleración motor, en 1/8 segundos
; 11) número de cilindros menos uno
; 12) velocidad de transferencia (en bits 6-7)
t360in360 DB 0DFh, 002h, 025h, 002h, 009h ; 360K en 360K
DB 02Ah, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 027h, 080h
t1200 DB 0DFh, 002h, 025h, 002h, 00Fh ; 1.2M
DB 01Bh, 0FFh, 054h, 0F6h, 00Fh
DB 008h, 04Fh, 000h
t720 DB 0DFh, 002h, 025h, 002h, 009h ; 720K
DB 02Ah, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 04Fh, 080h
t1440 DB 0BFh, 002h, 025h, 002h, 012h ; 1.44M
DB 01Bh, 0FFh, 06Ch, 0F6h, 00Fh
DB 008h, 04Fh, 000h
t360en1200 DB 0DFh, 002h, 025h, 002h, 009h ; 360K en 1.2M
DB 02Ah, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 027h, 040h
t2880 DB 0AFh, 002h, 025h, 002h, 024h ; 2.88M
DB 01Bh, 0FFh, 050h, 0F6h, 00Fh
DB 008h, 04Fh, 0C0h
; --- Fin del área residente para INT 40h
fin_residente EQU $
bytes_resid EQU fin_residente-ini_residente
; ------------ Rutina de gestión de INT 13h (si se necesita). Se llama
; a la INT 40h de manera que esta última no devuelva
; nunca errores de frontera de DMA, para lo que emplea un
; buffer auxiliar de 512 bytes para transferir el sector
; que cruzaría la frontera. En la función de formateo, al
; acceder a la primera pista del disco se invoca primero
; la interrupción original para que el DOS (cargado antes
; que este programa) se entere del cambio de soporte.
ges_int13 PROC
STI
CMP DL,80h
JB floppy
JMP CS:ant_int13
floppy: CMP AH,2
JB floppy_bios
CMP AH,5
JE test_format
JB test_rwv
floppy_bios: INT 40h ; función sin problemas de DMA
RETF 2
ges_int13 ENDP
test_format PROC
XPUSH <DS, ES, BX>
PUSHA
PUSH DX
OR DH,CH
POP DX
JNZ skip_aviso ; no es pista y cabezal 0
PUSHA
MOV AL,1 ; formatear un sector (AH=5)
MOV CH,0
MOV DH,2 ; en cabezal 2 (incorrecto)
PUSHF
CALL CS:ant_int13 ; avisar al DOS del nuevo disco
POPA
skip_aviso: MOV DI,CS:pbuffer
MOV SI,BX
PUSH ES
POP DS
PUSH CS
POP ES
MOV CX,256
CLD
REP MOVSW ; datos de formateo al buffer
POPA ; auxiliar
MOV BX,CS:pbuffer
INT 40h ; formateo
XPOP <BX, ES, DS> ; restaurar registros iniciales
RETF 2
test_format ENDP
test_rwv PROC ; para Read/Write/Verify
MOV CS:funcion,AH
MOV CS:nsects,AL
XPUSH <SI, DI>
XPUSH <AX, DX>
MOV AX,ES
MOV DX,16
MUL DX
ADD AX,BX
NEG AX ; AX = bytes hasta frontera DMA
SHR AX,9
MOV SI,AX ; sectores antes frontera
XPOP <DX, AX>
PUSH AX
MOV AH,0
MOV DI,AX
POP AX
CMP SI,DI
JBE trwv_no_sobra
MOV SI,DI
trwv_no_sobra: SUB DI,SI ; sectores+1 tras frontera
JZ trwv_1ok
PUSH CX
MOV CX,SI
MOV AL,CL ; AL sectores antes de frontera
POP CX
trwv_1ok: AND AL,AL
JZ trwv_1cruza ; primer sector cruza frontera
INT 40h
PUSHF
JNC trwv_cont ; sin fallo E/S
trwv_exit: JMP trwv_ret
trwv_cont: AND DI,DI
JZ trwv_exit ; se acabó
POPF
trwv_1cruza: CMP CS:funcion,3 ; ¿escritura?
JNE trwv_sectdma
PUSHA
XPUSH <DS, ES>
SHL SI,9 ; sectores transferidos * 512
ADD SI,BX
MOV DI,CS:pbuffer
PUSH ES
POP DS
PUSH CS
POP ES
MOV CX,256
CLD
REP MOVSW ; sector conflictivo a través
XPOP <ES, DS> ; de buffer auxiliar
POPA
trwv_sectdma: XPUSH <ES, BX, CX>
PUSH CS
POP ES
MOV BX,CS:pbuffer ; ES:BX buffer auxiliar
MOV AH,CS:funcion
MOV AL,1 ; un sector
ADD CX,SI ; nuevo sector inicial
INT 40h
XPOP <CX, BX, ES>
PUSHF
JC trwv_ret ; fallo E/S
CMP CS:funcion,2 ; ¿lectura?
JNE trwv_tras?
PUSHA
XPUSH <DS, ES>
SHL SI,9 ; sectores transferidos * 512
MOV DI,SI
ADD DI,BX
MOV SI,CS:pbuffer
PUSH CS
POP DS
MOV CX,256
CLD
REP MOVSW ; sector conflictivo a través
XPOP <ES, DS> ; de buffer auxiliar
POPA
trwv_tras?: MOV AL,CS:nsects ; sectores transferidos
DEC DI
JZ trwv_ret ; no queda nada tras frontera
POPF
XPUSH <BX, CX>
INC SI
ADD CX,SI ; nuevo sector inicial
SHL SI,9 ; sectores transferidos * 512
ADD BX,SI
MOV AX,DI ; sectores restantes
MOV AH,CS:funcion
INT 40h
XPOP <CX, BX>
MOV AL,CS:nsects ; número sectores transferidos
PUSHF
trwv_ret: POPF
XPOP <DI, SI>
RETF 2
test_rwv ENDP
funcion DB ?
nsects DB ?
pbuffer DW buffer_io
EVEN
buffer_io EQU $
; *****************************
; * *
; * I N S T A L A C I O N *
; * *
; *****************************
main PROC
ADD SP,2 ; quitar dirección de retorno
XPUSH <AX, BX, CX, DX, SI, DI, BP, DS, ES>
PUSH CS
POP DS
MOV WORD PTR interrupcion,531Eh ; opcode PUSH DS,BX
MOV BYTE PTR interrupcion+2,0BBh ; opcode MOV BX,??
PUSH CS
POP ES
CALL inic_general ; inicializar ciertas variables
CALL analiza_equipo
CALL lee_params ; parámetros de tipo unidades
CALL set_params ; actualizar tipo de unidades
CALL valida_drives ; asegurar que hay unidades
TEST error,0FFFFh
JNZ exit_ins
CALL hay2m?
JC no_2m
OR error,ERR_HAY2M ; 2M ó 2MX residente
JMP exit_ins
no_2m: TEST accion,I40 ; ¿soporta INT 40h el sistema?
JNZ i40_ok ; en efecto
CALL set_i13 ; añadir soporte vía INT 13h
i40_ok: CALL mx_get_handle ; obtener entrada Multiplex
JNC handle_ok
OR error,MX64FULL ; no quedan entradas
JMP exit_ins
handle_ok: MOV multiplex_id,AH ; entrada multiplex para 2M
CALL preservar_ints ; tomar nota de vectores
CALL activar_ints ; interceptar vectores
CALL set_dev_params ; establecer tipo unidades DOS
exit_ins: CALL info
MOV BX,pcab_pet_segm
MOV ES,BX
MOV BX,pcab_pet_desp
MOV WORD PTR ES:[BX+3],100h ; indicar retorno correcto
MOV AX,longitud_total
MOV CL,4
SHL AX,CL
TEST error,0FFFFh
JZ exit_ok
MOV WORD PTR ES:[BX+14],0 ; OFFSET 0: no quedará
MOV WORD PTR ES:[BX+16],CS ; instalado en memoria
JMP exit_interr
exit_ok: MOV WORD PTR ES:[BX+14],AX ; OFFSET al último byte residente
MOV WORD PTR ES:[BX+16],CS
exit_interr: XPOP <ES, DS, BP, DI, SI, DX, CX, BX, AX>
RETF
main ENDP
; ------------ Leer los parámetros en la línea del CONFIG (ES:BX).
lee_params PROC
PUSH ES
MOV BX,pcab_pet_segm
MOV ES,BX
MOV BX,pcab_pet_desp
LES BX,ES:[BX+12h] ; apuntar a los parámetros
CALL salta_nombre ; buscar inicio parámetros
mas_param: CALL busca_param ; saltar delimitadores
JC fin_params ; no hay parámetros
otro_drive: CMP AX,':a'
JE unidad_ok
CMP AX,':b' ; admitidas A: y B:
JE unidad_ok
param_error: OR error,ERR_SYNTAX ; error de sintaxis
POP ES
RET
unidad_ok: MOV CL,ES:[BX+2]
SUB CL,'0' ; tipo de la unidad
SUB AL,'a'
MOV AH,0
LEA DI,tipos_drv
ADD DI,AX
CMP CL,5 ; ¿tipo entre 0 y 5?
JA param_error
MOV [DI],CL ; definir tipo
ADD BX,3
JMP mas_param ; próximo parámetro
fin_params: POP ES
RET
lee_params ENDP
salta_nombre PROC ; saltar nombre del driver en
MOV AL,ES:[BX] ; línea de órdenes del CONFIG
INC BX
CMP AL,' '
JE fin_nombre
CMP AL,9
JE fin_nombre
CMP AL,0Dh
JE fin_nombre
CMP AL,0Ah
JE fin_nombre
AND AL,AL
JZ fin_nombre
JMP salta_nombre
fin_nombre: RET
salta_nombre ENDP
busca_param PROC ; saltar delimitadores
DEC BX
p_delimit: INC BX
MOV AX,ES:[BX]
CMP AL,' '
JE p_delimit ; espacio en blanco
CMP AL,9
JE p_delimit ; tabulador
CMP AL,13
JE p_final ; CR ó LF indican el final
CMP AL,10
JE p_final
OR AX," " ; poner en minúsculas
CLC
RET
p_final: STC ; se acabaron los parámetros
RET
busca_param ENDP
; ------------ Establecer tipo disqueteras (según BIOS o parámetros).
set_params PROC
PUSH ES
MOV AL,tipos_drv
CMP AL,-1
JNE ta_calc ; A: definida por el usuario
MOV AH,8
MOV DL,0
INT 13h ; consultar tipo a la BIOS
MOV AL,BL
JNC ta_val
JMP set_type_exit ; unidad no existente
ta_val: CMP DL,1
JB set_type_exit
ta_calc: CMP AL,4
JBE ta_set
MOV AL,5 ; 2.88M representado por 5
ta_set: AND tipo_drvs,0Fh
MOV CL,4
SHL AL,CL
OR tipo_drvs,AL ; tipo A: en nibble alto
MOV AL,tipos_drv+1
CMP AL,-1 ; B: definida por el usuario
JNE tb_calc
MOV AH,8
MOV DL,1
INT 13h ; consultar tipo a la BIOS
MOV AL,BL
JC set_type_exit
CMP DL,2
JB set_type_exit ; unidad no existente
tb_calc: CMP AL,4
JBE tb_set
MOV AL,5 ; 2.88M representado por 5
tb_set: AND tipo_drvs,0F0h
OR tipo_drvs,AL ; tipo B: en nibble bajo
set_type_exit: POP ES
RET
set_params ENDP
; ------------ Asegurar que se conoce el tipo de las unidades.
valida_drives PROC
MOV AL,tipo_drvs
AND AL,0F0h
JNZ drvs_ok
OR error,ERR_MALDRV
drvs_ok: RET
valida_drives ENDP
; ------------ Código ejecutado desde la línea de comandos.
inicio PROC FAR
MOV AX,_PRINCIPAL
MOV DS,AX
CALL param_i?
LEA DX,info_txt
CALL print
MOV AX,4C00h
INT 21h ; final normal
inicio ENDP
; ----- Buscar posible parámetro /I
param_i? PROC
MOV DI,80h
MOV CL,ES:[DI]
MOV CH,0
INC CX
busca_mas: MOV DL,OFF
JCXZ ret_bparam
busca_barra: INC DI
CMP BYTE PTR ES:[DI],'/'
LOOPNE busca_barra
JNE ret_bparam
MOV AL,ES:[DI+1]
OR AL,32
CMP AL,'i'
MOV DL,ON
JE ret_bparam
JMP busca_mas
ret_bparam: MOV param_i,DL
RET
param_i? ENDP
; ------------ Inicializar ciertas variables.
inic_general PROC
MOV AX,(bytes_resid+15)/16
MOV longitud_total,AX ; memoria necesaria
MOV segmento_real,CS ; anotar segmento del bloque
MOV offset_real,0 ; ídem con el offset
RET
inic_general ENDP
; ------------ Comprobar que la configuración es la adecuada. Para
; saber si la INT 13h de este ordenador acaba llamando a
; la INT 40h, se desvía la INT 40h y se provoca un inocuo
; reset de disquetes vía INT 13h para comprobar si pasa
; por la INT 40h.
analiza_equipo PROC
PUSH ES
CALL testAT
MOV AX,ERR_TIPOPC
JC cod_err_ok ; no es AT o superior
CALL test_i40
XOR AX,AX
cod_err_ok: OR error,AX
POP ES
RET
analiza_equipo ENDP
; --- Comprobar si la INT 40h está en uso
test_i40: XPUSH <DS, ES> ; *
MOV AX,3540h
INT 21h
XPUSH <ES, BX> ; vector de INT 40h original
LEA DX,i40_aux
MOV AX,2540h
INT 21h ; establecer nueva INT 40h
XOR AX,AX
MOV DL,0
INT 13h ; reset de disco
XPOP <DX, DS>
MOV AX,2540h
INT 21h ; restaurar INT 40h original
XPOP <ES, DS> ; *
RET
i40_aux PROC
OR CS:accion,I40 ; sí utilizada INT 40h
IRET ; desde la INT 13h
i40_aux ENDP
; ----- Detectar 286 ó superior.
testAT PROC
PUSHF
POP AX
OR AH,70h ; intentar activar bit 12, 13 ó 14
PUSH AX ; del registro de estado
POPF
PUSHF
POP AX
AND AH,0F0h
CMP AH,0F0h
JE testedAT
STC
testedAT: CMC ; CF = 0 en AT y 1 en PC/XT
RET
testAT ENDP
; ------------ Desviar también INT 13h ya que en esta máquina el
; gestor de INT 13h no invoca la INT 40h.
set_i13 PROC
INC offsets_ints ; usado un vector más
INC BYTE PTR tabla_vectores-1
MOV AX,CS
MOV CX,16
MUL CX
ADD AX,pbuffer
ADC DX,0 ; DX:AX = dirección 20 bits
MOV CX,DX
PUSH AX
ADD AX,511 ; buffer para el mayor sector
ADC DX,0
POP AX
CMP DX,CX
JE dma_ok
NEG AX
ADD pbuffer,AX ; saltar hasta próxima frontera
OR accion,BUFFERPLUS
dma_ok: MOV AX,pbuffer
ADD AX,512
SUB AX,OFFSET ges_int13
ADD AX,15
MOV CL,4
SHR AX,CL
ADD longitud_total,AX ; es necesaria más memoria
RET
set_i13 ENDP
; ------------ Establecer el tipo de las unidades a nivel DOS.
set_dev_params PROC
MOV AH,30h
INT 21h
XCHG AH,AL
CMP AX,314h
JB dev_set ; DOS < 3.2 -> no soportado
MOV BX,1
set_otro_dev: PUSH BX
MOV AH,8
MOV DL,BL
DEC DL
PUSH BX
PUSH ES
INT 13h ; obtener tipo de la unidad
POP ES
MOV BH,0
SHL BX,1
ADD BX,OFFSET ptr_dev_info
MOV DX,[BX] ; DS:DX -> tabla de información
POP BX
AND DX,DX
JZ device_set
MOV AX,440Dh ; IOCTL
MOV CX,0840h
INT 21h ; establecer tipo de soporte
device_set: POP BX
INC BX
CMP BX,2
JBE set_otro_dev
dev_set: RET
set_dev_params ENDP
; ------------ Preservar vectores de interrupción previos.
preservar_INTs PROC
XPUSH <ES, DI>
LEA DI,tabla_vectores
MOV CL,[DI-1]
MOV CH,0 ; CX vectores interceptados
otro_vector: XPUSH <CX, DI>
MOV AH,35h
MOV AL,[DI]
INT 21h ; obtener vector de INT xx
XPOP <DI, CX>
MOV [DI+1],BX ; anotar donde apunta
MOV [DI+3],ES
ADD DI,5
LOOP otro_vector ; repetir con los restantes
XPOP <DI, ES>
RET
preservar_INTs ENDP
; ------------ desviar vectores de interrupción a las nuevas rutinas.
activar_INTs PROC
LEA SI,offsets_ints
MOV CX,CS:[SI] ; CX vectores a desviar
ADD SI,2
desvia_otro: MOV AL,CS:[SI] ; número del vector en curso
MOV DX,CS:[SI+1] ; obtener offset
MOV AH,25h
INT 21h ; desviar INT xx a DS:DX
ADD SI,3
LOOP desvia_otro
RET
activar_INTs ENDP
; ------------ Buscar entrada no usada en la interrupción Multiplex.
; A la salida, CF=1 si no hay hueco (ya hay 64 programas
; residentes instalados con esta técnica). Si CF=0, se
; devuelve en AH un valor de entrada libre en la INT 2Fh.
mx_get_handle PROC
MOV AH,0C0h
mx_busca_hndl: PUSH AX
MOV AL,0
INT 2Fh
CMP AL,0FFh
POP AX
JNE mx_si_hueco
INC AH
JNZ mx_busca_hndl
STC
RET
mx_si_hueco: CLC
RET
mx_get_handle ENDP
; ------------ Devolver CF=0 si 2M o 2MX están instalados o se ha
; cargado el código 2M en modo SuperBOOT.
hay2m? PROC
PUSH ES
LEA SI,id_2m ; identificación del programa
MOV CX,id_2m_tam
MOV AX,1492h
MOV ES,AX
MOV DI,1992h ; ES:DI protocolo de búsqueda
CALL mx_find_tsr ; buscar si está en memoria
JNC hay2m?_ret
LEA SI,id_2mx ; identificación del programa
MOV CX,id_2mx_tam
CALL mx_find_tsr
JNC hay2m?_ret
INT 12h ; tamaño memoria convencional
CMP AX,640
JBE base_sc_ok
MOV AX,640 ; alguien la ha manipulado
base_sc_ok: SUB AX,5
MOV BX,64
MUL BX ; AX = segmento de SuperBOOT
MOV CX,6
scan_boot: PUSH CX
MOV ES,AX
MOV DI,6
LEA SI,id_boot
MOV CX,id_boot_tam
CLD
REP CMPSB
POP CX
JE hay2m?_ret ; CF = 0 -> 2M SuperBOOT
SUB AX,1000h
LOOP scan_boot ; buscar 64K más abajo
STC
hay2m?_ret: POP ES
RET
hay2m? ENDP
; ------------ Buscar un TSR por la interrupción Multiplex. A la
; entrada, DS:SI cadena de identificación del programa
; (CX bytes) y ES:DI protocolo de búsqueda (normalmente
; 1492h:1992h). A la salida, si el TSR ya está instalado,
; CF=0 y ES:DI apunta a la cadena de identificación del
; mismo. Si no, CF=1 y ningún registro alterado.
mx_find_tsr PROC
MOV AH,0C0h
mx_rep_find: XPUSH <AX, CX, SI, DS, ES, DI>
MOV AL,0
PUSH CX
INT 2Fh
POP CX
CMP AL,0FFh
JNE mx_skip_hndl ; no hay TSR ahí
CLD
PUSH DI
REP CMPSB ; comparar identificación
POP DI
JE mx_tsr_found ; programa buscado hallado
mx_skip_hndl: XPOP <DI, ES, DS, SI, CX, AX>
INC AH
JNZ mx_rep_find
STC
RET
mx_tsr_found: ADD SP,4 ; «sacar» ES y DI de la pila
XPOP <DS, SI, CX, AX>
CLC
RET
mx_find_tsr ENDP
; ------------ Informar al usuario.
info PROC
TEST error,0FFFFh
JZ info_mas
LEA DX,no_inst_txt
CALL print
LEA DX,mal_cpu_txt
TEST error,ERR_TIPOPC
JNZ print_err
LEA DX,hay2m_txt
TEST error,ERR_HAY2M
JNZ print_err
LEA DX,null_drv_txt
TEST error,ERR_MALDRV
JNZ print_err
LEA DX,err_syntax_txt
TEST error,ERR_SYNTAX
JNZ print_err
LEA DX,err_mx64full
TEST error,MX64FULL
JZ fin_info
print_err: CALL print
RET
info_mas: LEA DX,instalado_txt
CALL print
CALL info_drives
TEST accion,BUFFERPLUS
JZ fin_info
LEA DX,dma_cross_txt
CALL print
fin_info: RET
info ENDP
; --- Informar de las unidades controladas.
info_drives PROC
MOV AH,8
MOV DL,0
INT 13h
JC info_null ; no hay información sobre A:
AND BL,BL
JZ info_null
CMP DL,1
JB info_null
PUSH DX
MOV BH,0
DEC BX
SHL BX,1
LEA DX,a_txt ; "A:"
CALL print
MOV DX,[BX+OFFSET ptr_txt_tipos] ; su tipo
CALL print
POP DX
CMP DL,2
JB info_exit ; no hay información sobre B:
MOV AH,8
MOV DL,1
INT 13h
JC info_exit
AND BL,BL
JZ info_exit
MOV BH,0
DEC BX
SHL BX,1
LEA DX,b_txt ; "B:"
CALL print
MOV DX,[BX+OFFSET ptr_txt_tipos] ; su tipo
CALL print
info_exit: LEA DX,i40_txt
TEST accion,I40
JNZ imodo_ok
LEA DX,i13_txt
imodo_ok: CALL print ; modo de instalación
RET
info_null: LEA DX,null_drv_txt ; sin indicar tipo de unidades
CALL print
RET
info_drives ENDP
; ------------ Inicializar variable idioma_sp según idioma del país.
habla_hispana? PROC
XPUSH <AX, BX, CX, DX, BP>
MOV AH,30h
INT 21h
XCHG AH,AL ; AX = versión del DOS
MOV BP,AX
MOV idioma_sp,OFF ; supuesto de habla no hispana
CMP BP,200h
JB habla_ok
LEA DX,buffer_aux
MOV AX,3800h
INT 21h ; obtener información del pais
CMP BP,20Bh
JE habla_ax ; DOS 2.11: AX cód. telefónico
CMP BP,300h
JB habla_ok ; 2.x excepto 2.11: mala suerte
MOV AX,BX
habla_ax: LEA BX,paises_sp-2
MOV CX,numpaises_sp
habla_sp?: ADD BX,2
CMP AX,[BX]
JE habla_hispana
LOOP habla_sp?
habla_ok: MOV AL,param_i
XOR idioma_sp,AL ; considerar parámetro /I
XPOP <BP, DX, CX, BX, AX>
RET
habla_hispana: MOV idioma_sp,ON ; país de habla hispana
MOV AL,param_i
XOR idioma_sp,AL ; considerar parámetro /I
XPOP <BP, DX, CX, BX, AX>
RET
habla_hispana? ENDP
; ------------ Imprimir cadena en DS:DX delimitada por un 0 ó un 255.
; Si hay que imprimir en inglés se toma la cadena que va
; después si ésta acaba en 255 (si acaba en 0, no hay
; distinción entre mensaje castellano e inglés).
print PROC
XPUSH <AX, BX, CX, DX>
pr_decidir: CMP idioma_sp,OFF
JE usar_uk
CMP idioma_sp,ON
JE usar_sp
PUSH DX
CALL habla_hispana? ; determinar lengua
POP DX
JMP pr_decidir
usar_uk: MOV BX,DX
DEC BX
usar_uk?: INC BX
CMP BYTE PTR [BX],0
JE usar_sp ; acaba en 0: no traducir
CMP BYTE PTR [BX],255
JNE usar_uk?
LEA DX,[BX+1] ; acaba en 255: traducir
usar_sp: MOV BX,DX
DEC BX
print_cad: INC BX
CMP BYTE PTR [BX],0
JE prlong_ok
CMP BYTE PTR [BX],255
JNE print_cad ; calcular longitud
prlong_ok: MOV CX,BX
SUB CX,DX
MOV AH,40h
MOV BX,1
INT 21h
XPOP <DX, CX, BX, AX>
RET
print ENDP
; ************ Datos no residentes para la instalación
ON EQU 1 ; constantes booleanas
OFF EQU 0
param_i DB OFF ; a ON si indicado parámetro /I
tipos_drv DB -1 ; tipo de A:
DB -1 ; y de B:
id_2m DB "CiriSOFT:2M:" ; marcas de presencia de 2M
id_2m_tam EQU $-OFFSET id_2m
id_2mx DB "CiriSOFT:2MX:"
id_2mx_tam EQU $-OFFSET id_2mx
id_boot DB "2M-STV"
id_boot_tam EQU $-OFFSET id_boot
ERR_TIPOPC EQU 1 ; códigos de error
ERR_HAY2M EQU 2
ERR_MALDRV EQU 4
ERR_SYNTAX EQU 8
MX64FULL EQU 16
I40 EQU 1 ; códigos de acción
BUFFERPLUS EQU 2
offsets_ints DW 2 ; número de vectores interceptados
DB 2Fh ; tabla de offsets de los vectores
DW ges_int2F ; de interrupción interceptados
DB 40h
DW ges_int40
DB 13h ; INT 13h podría usarse
DW ges_int13
ptr_dev_info DW 0, i360, i1200, i720, i1440, i2880
i360 DB 4, 0 ; sectores iguales / tipo 360K
DW 0, 40 ; no detecta cambio / nº pistas
DB 1 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 2 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 112 ; BPB: entradas en el raíz
DW 720 ; BPB: nº total de sectores
DB 0FDh ; BPB: descriptor de medio
DW 2 ; BPB: sectores por FAT
DW 9, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i1200 DB 4, 1 ; sectores iguales / tipo 1.2M
DW 2, 80 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 1 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 224 ; BPB: entradas en el raíz
DW 2400 ; BPB: nº total de sectores
DB 0F9h ; BPB: descriptor de medio
DW 7 ; BPB: sectores por FAT
DW 15, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i720 DB 4, 2 ; sectores iguales / tipo 720K
DW 0, 80 ; no detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 2 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 112 ; BPB: entradas en el raíz
DW 1440 ; BPB: nº total de sectores
DB 0F9h ; BPB: descriptor de medio
DW 3 ; BPB: sectores por FAT
DW 9, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i1440 DB 4, 7 ; sectores iguales / tipo 1.44M
DW 2, 80 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 1 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 224 ; BPB: entradas en el raíz
DW 2880 ; BPB: nº total de sectores
DB 0F0h ; BPB: descriptor de medio
DW 9 ; BPB: sectores por FAT
DW 18, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
i2880 DB 4, 9 ; sectores iguales / tipo 2.88M
DW 2, 80 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 512 ; BPB: bytes por sector
DB 2 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 2 ; BPB: número de FATs
DW 224 ; BPB: entradas en el raíz
DW 5760 ; BPB: nº total de sectores
DB 0F0h ; BPB: descriptor de medio
DW 9 ; BPB: sectores por FAT
DW 36, 2 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
accion DW 0
error DW 0
idioma_sp DB 5Ah ; ni en ON ni en OFF al principio
; --- Código telefónico de países de
; habla hispana (mucha o poca).
paises_sp DW 54 ; Argentina
DW 591 ; Bolivia
DW 57 ; Colombia
DW 506 ; Costa Rica
DW 56 ; Chile
DW 593 ; Ecuador
DW 503 ; El Salvador
DW 34 ; España
DW 63 ; Filipinas
DW 502 ; Guatemala
DW 504 ; Honduras
DW 212 ; Marruecos
DW 52 ; México
DW 505 ; Nicaragua
DW 507 ; Panamá
DW 595 ; Paraguay
DW 51 ; Perú
DW 80 ; Puerto Rico
DW 508 ; República Dominicana
DW 598 ; Uruguay
DW 58 ; Venezuela
DW 3 ; genérico latinoamérica
numpaises_sp EQU ($-OFFSET paises_sp)/2
; ------------ Texto.
instalado_txt DB 13,10,"2M-ABIOS 1.2 instalado en ",255
DB 13,10,"2M-ABIOS 1.2 installed on ",0
a_txt DB "A:",0
b_txt DB " y B:",255," and B:",0
ptr_txt_tipos DW d360, d1200, d720, d1440, d2880
d360 DB "360K",0
d1200 DB "1.2M",0
d720 DB "720K",0
d1440 DB "1.44M",0
d2880 DB "2.88M",0
i40_txt DB " [INT 40h]",13,10,0
i13_txt DB " [INT 13h]",13,10,0
no_inst_txt DB 13,10,"2M-ABIOS 1.2 *NO* instalado.",13,10,255
DB 13,10,"2M-ABIOS 1.2 *NOT* installed.",13,10,0
mal_cpu_txt DB " + Error: necesario equipo AT ó superior. Utilice 2M-XBIOS en este equipo.",13,10,255
DB " + Error: needs AT or upper system. Try 2M-XBIOS on this system.",13,10,0
hay2m_txt DB " + Error: 2M-ABIOS debe instalarse *ANTES* de 2M (y nunca en SuperBOOT).",13,10,255
DB " + Error: 2M-ABIOS must be installed *BEFORE* 2M (and never in SuperBOOT).",13,10,0
null_drv_txt DB " + Utilice los parámetros para indicar expresamente el tipo de las unidades.",13,10,255
DB " + Please use the switches to set the correct diskette drives type.",13,10,0
err_syntax_txt DB " + Error de sintaxis: ejecútelo desde el símbolo DOS para obtener ayuda.",13,10,255
DB " + Syntax error: execute from DOS command line to obtain help.",13,10,0
err_mx64full DB " + Error: Ya hay 64 programas residentes con la misma técnica.",13,10,7,255
DB " + Error: There are already 64 TSR's with the same technique.",13,10,7,0
dma_cross_txt DB " - Nota: El buffer de E/S cruzaba una frontera de DMA y fue ampliado.",13,10
DB " Cambie la ubicación en memoria si desea ahorrar unos bytes.",13,10,255
DB " - Note: I/O buffer has been extended because it crosses a DMA boundary.",13,10
DB " Modify the memory location of 2M-ABIOS to save a little memory.",13,10,0
info_txt LABEL BYTE
DB 13,10
DB " 2M-ABIOS 1.2 - (c) Mayo 1994 Ciriaco García de Celis.",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10,10
DB " Sintaxis: DEVICE=2M-ABIOS.EXE [A:tipo [B:tipo]]",13,10,10
DB " Algunos ordenadores poseen una BIOS antigua o con un diseño propio poco",13,10
DB " compatible en el control de disco. En estas máquinas 2M y otros programas",13,10
DB " de acceso a bajo nivel pueden fallar. En dichos casos, conviene instalar",13,10
DB " esta utilidad antes que 2M, y en general que cualquier otro software que",13,10
DB " acceda al subsistema de disco. Este programa es sólo para máquinas AT.",13,10,10
DB " 2M-ABIOS actualiza el soporte de disco flexible a la última tecnología",13,10
DB " de las BIOS AMI de 1993. Si con 2M-ABIOS instalado 2M no opera de manera",13,10
DB " totalmente correcta y en su máquina no está instalado algún otro software",13,10
DB " de disco incompatible con 2M, entonces su ordenador no es 100% compatible",13,10
DB " hardware con el estándar; esto es particularmente cierto si con 2M-ABIOS",13,10
DB " instalado no se reconocen siquiera los discos estándar del DOS.",13,10,10
DB " Este programa ocupa 3.4-4.2 Kb de RAM, y contiene una emulación al 100%",13,10
DB " del eficaz código de control de disco de las BIOS AMI, relevando así por",13,10
DB " completo de esta tarea a la BIOS del sistema. Generalmente no hará falta",13,10
DB " indicar el tipo (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M). AMI",13,10
DB " es marca registrada de American Megatrends Inc.",13,10
DB 255
DB 13,10,10
DB " 2M-ABIOS 1.2 - (c) Mayo 1994 Ciriaco García de Celis.",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10,10
DB " Syntax: DEVICE=2M-ABIOS.EXE [A:type [B:type]]",13,10,10
DB " Some computers have an old BIOS or a BIOS built with a peculiar design,",13,10
DB " few compatible in disk operation. In those systems 2M and other low-level",13,10
DB " software can fails. In these cases you can install 2M-ABIOS before 2M and",13,10
DB " before any other disk TSR software. This program is only for use on AT",13,10
DB " computer systems.",13,10,10
DB " 2M-ABIOS upgrades floppy-disk support to last AMI BIOS 1993 technology.",13,10
DB " If 2M-ABIOS is installed, and 2M continues not working full correctly on",13,10
DB " your computer, and is not installed in the system any other disk software",13,10
DB " incompatible with 2M, this probably means that your computer is not 100%",13,10
DB " hardware compatible with the standard AT; this is specially true if only",13,10
DB " 2M-ABIOS is installed and DOS standard diskettes don't work.",13,10,10
DB " This program takes 3.4-4.2 Kb of RAM, and provides a full emulation of",13,10
DB " the effective disk control management of AMI BIOS, absolutely overriding",13,10
DB " your native BIOS in this job. Usually you do not need to select the drive",13,10
DB " type (0:not present, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M). AMI is a",13,10
DB " registered trademark of American Megatrends Inc.",13,10
DB 0
buffer_aux DB 64 DUP (0) ; buffer para alguna función del DOS
_PRINCIPAL ENDS
_PILA SEGMENT STACK 'STACK'
DB 1024 DUP (?) ; 1 Kb de pila es suficiente
_PILA ENDS
END inicio